import os
import sys
import sqlite3
import ctypes
import subprocess
import datetime
import shutil
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                            QTableView, QPushButton, QProgressDialog, QLabel, QLineEdit,
                            QHeaderView, QMenu, QAction, QMessageBox, QFileDialog, QSplitter,
                            QInputDialog, QCheckBox, QGroupBox, QGridLayout, QComboBox,
                            QFrame)
from PyQt5.QtCore import Qt, QAbstractTableModel, QThread, pyqtSignal, QModelIndex
from PyQt5.QtGui import QFont, QColor

# 启用长路径支持（Windows）
try:
    ctypes.windll.kernel32.SetDllDirectoryW(None)
    ctypes.windll.kernel32._wow64_disableWow64FsRedirection(ctypes.byref(ctypes.c_long()))
except:
    pass

class ScanThread(QThread):
    """文件扫描线程"""
    progress_updated = pyqtSignal(int)
    file_found = pyqtSignal(dict)
    scan_finished = pyqtSignal()

    def __init__(self, root_paths, extensions=None):
        super().__init__()
        self.root_paths = root_paths
        # 完全尊重从UI传递过来的extensions值，不设置默认值
        self.extensions = extensions if extensions is not None else []
        self.running = True
        self.found_files = []

    def run(self):
        total_files = 0
        for root_path in self.root_paths:
            if not self.running:
                break
                
            for dirpath, _, filenames in os.walk(root_path):
                if not self.running:
                    break
                    
                for filename in filenames:
                    if not self.running:
                        break
                        
                    # 检查文件扩展名是否在指定的列表中
                    if any(filename.lower().endswith(ext.lower()) for ext in self.extensions):
                        try:
                            full_path = os.path.join(dirpath, filename)
                            file_size = os.path.getsize(full_path)
                            # 获取文件创建时间
                            creation_time = os.path.getctime(full_path)
                            # 格式化为可读时间
                            formatted_time = datetime.datetime.fromtimestamp(creation_time).strftime('%Y-%m-%d %H:%M:%S')
                            
                            file_info = {
                                'name': filename,
                                'path': full_path,
                                'size': self.format_size(file_size),
                                'ext': filename.split('.')[-1].upper(),
                                'created': formatted_time
                            }
                            self.found_files.append(file_info)
                            self.file_found.emit(file_info)
                        except Exception as e:
                            continue
                            
                    total_files += 1
                    if total_files % 100 == 0:
                        self.progress_updated.emit(total_files)
        
        self.scan_finished.emit()

    def stop(self):
        self.running = False

    @staticmethod
    def format_size(size_bytes):
        """格式化文件大小为人类可读形式"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.2f} {unit}"
            size_bytes /= 1024.0
        return f"{size_bytes:.2f} TB"

class FileTableModel(QAbstractTableModel):
    """文件列表表格模型"""
    def __init__(self):
        super().__init__()
        self.files = []
        self.headers = ['文件名', '类型', '大小', '创建时间', '路径']

    def rowCount(self, parent=QModelIndex()):
        return len(self.files)

    def columnCount(self, parent=QModelIndex()):
        return len(self.headers)

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid() or index.row() >= len(self.files):
            return None

        file = self.files[index.row()]
        col = index.column()

        if role == Qt.DisplayRole:
            if col == 0:
                return file['name']
            elif col == 1:
                return file['ext']
            elif col == 2:
                return file['size']
            elif col == 3:
                return file.get('created', '')
            elif col == 4:
                return file['path']
                
        elif role == Qt.BackgroundRole:
            # 交替行颜色
            if index.row() % 2 == 0:
                return QColor(245, 245, 245)
            return QColor(255, 255, 255)
            
        elif role == Qt.TextAlignmentRole:
            # 确保"类型"列(索引1)与"文件名"列(索引0)对齐方式一致
            if col == 2 or col == 3:
                return Qt.AlignRight | Qt.AlignVCenter
            # 文件名和类型列都使用左对齐
            return Qt.AlignLeft | Qt.AlignVCenter

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.headers[section]
        return None

    def add_file(self, file_info):
        """添加文件到模型"""
        self.beginInsertRows(QModelIndex(), len(self.files), len(self.files))
        self.files.append(file_info)
        self.endInsertRows()

    def clear_files(self):
        """清空文件列表"""
        self.beginResetModel()
        self.files = []
        self.endResetModel()

    def get_file(self, row):
        """获取指定行的文件信息"""
        if 0 <= row < len(self.files):
            return self.files[row]
        return None

class PPTScanner(QMainWindow):
    """文件扫描主窗口"""
    def __init__(self):
        super().__init__()
        self.scan_thread = None
        self.selected_extensions = []  # 初始化为空列表，无默认选择的文件类型
        self.init_ui()
        self.init_db()

    def init_ui(self):
        """初始化界面"""
        self.setWindowTitle("文件扫描工具")
        self.setGeometry(100, 100, 1200, 700)
        self.setMinimumSize(800, 500)

        # 中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # 顶部控制区
        control_layout = QHBoxLayout()
        
        # 扫描路径选择
        self.path_label = QLabel("扫描路径:")
        self.path_input = QLineEdit()
        self.path_input.setPlaceholderText("选择要扫描的目录...")
        self.browse_btn = QPushButton("浏览...")
        self.browse_btn.clicked.connect(self.browse_directory)
        
        # 文件类型选择
        self.create_file_type_selector(control_layout)
        
        # 扫描按钮
        self.scan_btn = QPushButton("开始扫描")
        self.scan_btn.clicked.connect(self.start_scan)
        self.stop_btn = QPushButton("停止扫描")
        self.stop_btn.clicked.connect(self.stop_scan)
        self.stop_btn.setEnabled(False)
        
        # 搜索区域
        search_layout = QHBoxLayout()
        
        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("搜索文件名...")
        
        # 搜索模式选择
        self.search_mode = QComboBox()
        self.search_mode.addItems(["任意字符", "完全匹配", "备注搜索"])
        
        # 搜索按钮
        self.search_btn = QPushButton("搜索")
        self.search_btn.clicked.connect(self.filter_files)
        
        # 重置按钮
        self.reset_btn = QPushButton("重置")
        self.reset_btn.clicked.connect(self.reset_search)
        
        # 添加到搜索布局
        search_layout.addWidget(QLabel("搜索:"))
        search_layout.addWidget(self.search_input, 2)
        search_layout.addWidget(QLabel("模式:"))
        search_layout.addWidget(self.search_mode, 1)
        search_layout.addWidget(self.search_btn)
        search_layout.addWidget(self.reset_btn)
        
        # 添加分隔线
        line = QFrame()
        line.setFrameShape(QFrame.VLine)
        line.setFrameShadow(QFrame.Sunken)
        control_layout.addWidget(line)
        
        # 添加到布局
        control_layout.addWidget(self.path_label)
        control_layout.addWidget(self.path_input, 2)
        control_layout.addWidget(self.browse_btn)
        control_layout.addWidget(self.scan_btn)
        control_layout.addWidget(self.stop_btn)
        
        # 添加搜索布局
        control_layout.addLayout(search_layout, 3)
        
        # 连接文本变化事件，当文本清空时自动重置搜索
        self.search_input.textChanged.connect(self.on_search_text_changed)

        # 文件列表表格
        self.file_model = FileTableModel()
        self.file_table = QTableView()
        self.file_table.setModel(self.file_model)
        self.file_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 将"文件名"列设置为可交互调整宽度
        self.file_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive)
        # 将"类型"列设置为可交互调整宽度，与"文件名"列对齐
        self.file_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Interactive)
        # 设置"类型"列的初始宽度
        self.file_table.setColumnWidth(1, 60)
        # 将"大小"列设置为可交互调整宽度，与"类型"列对齐
        self.file_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Interactive)
        # 设置"大小"列的初始宽度
        self.file_table.setColumnWidth(2, 80)
        # 将"创建时间"列设置为可交互调整宽度，与"类型"列对齐
        self.file_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Interactive)
        # 设置"创建时间"列的初始宽度
        self.file_table.setColumnWidth(3, 120)
        self.file_table.setAlternatingRowColors(True)
        self.file_table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.file_table.customContextMenuRequested.connect(self.show_context_menu)
        self.file_table.doubleClicked.connect(self.open_file_location)
        
        # 设置表格字体
        font = QFont("Microsoft YaHei", 9)
        self.file_table.setFont(font)

        # 添加到主布局
        main_layout.addLayout(control_layout)
        main_layout.addWidget(self.file_table)

        # 状态栏
        self.statusBar().showMessage("就绪")
        self.count_label = QLabel("找到: 0 个文件")
        self.statusBar().addPermanentWidget(self.count_label)

    def init_db(self):
        """初始化数据库"""
        try:
            conn = sqlite3.connect('ppt_scanner.db')
            c = conn.cursor()
            c.execute('''CREATE TABLE IF NOT EXISTS file_notes
                         (path TEXT PRIMARY KEY, note TEXT)''')
            conn.commit()
            conn.close()
        except Exception as e:
            QMessageBox.warning(self, "数据库错误", f"初始化数据库失败: {str(e)}")

    def browse_directory(self):
        """浏览选择目录"""
        directory = QFileDialog.getExistingDirectory(self, "选择扫描目录")
        if directory:
            self.path_input.setText(directory)

    def create_file_type_selector(self, parent_layout):
        """创建文件类型选择器"""
        # 文件类型选择组
        type_group = QGroupBox("文件类型:")
        type_layout = QGridLayout()
        
        # 常用文件类型复选框
        self.file_type_checkboxes = {
            # 文档类型
            '.ppt': QCheckBox("PPT"),
            '.pptx': QCheckBox("PPTX"),
            '.doc': QCheckBox("DOC"),
            '.docx': QCheckBox("DOCX"),
            '.pdf': QCheckBox("PDF"),
            '.xls': QCheckBox("XLS"),
            '.xlsx': QCheckBox("XLSX"),
            # 代码文件类型
            '.py': QCheckBox("Python"),
            # 图片类型
            '.jpg': QCheckBox("JPG"),
            '.jpeg': QCheckBox("JPEG"),
            '.png': QCheckBox("PNG"),
            '.gif': QCheckBox("GIF"),
            '.bmp': QCheckBox("BMP"),
            '.tiff': QCheckBox("TIFF"),
            # 视频类型
            '.mp4': QCheckBox("MP4"),
            '.avi': QCheckBox("AVI"),
            '.mov': QCheckBox("MOV"),
            '.wmv': QCheckBox("WMV"),
            '.flv': QCheckBox("FLV"),
            '.mkv': QCheckBox("MKV")
        }
        
        # 设置默认选中状态
        for ext, checkbox in self.file_type_checkboxes.items():
            if ext in self.selected_extensions:
                checkbox.setChecked(True)
            checkbox.stateChanged.connect(self.on_file_type_changed)
        
        # 添加到布局（3列布局）
        row, col = 0, 0
        for checkbox in self.file_type_checkboxes.values():
            type_layout.addWidget(checkbox, row, col)
            col += 1
            if col >= 3:
                col = 0
                row += 1
        
        type_group.setLayout(type_layout)
        parent_layout.addWidget(type_group)
    
    def on_file_type_changed(self):
        """文件类型选择变化时更新选中的扩展名列表"""
        self.selected_extensions = []
        for ext, checkbox in self.file_type_checkboxes.items():
            if checkbox.isChecked():
                self.selected_extensions.append(ext)
        # 移除自动选择默认类型的逻辑，允许用户不选择任何类型
    
    def start_scan(self):
        """开始扫描"""
        path = self.path_input.text()
        if not path or not os.path.isdir(path):
            QMessageBox.warning(self, "路径错误", "请选择有效的扫描目录")
            return

        # 重置界面
        self.file_model.clear_files()
        self.count_label.setText("找到: 0 个文件")
        
        # 启动扫描线程，传递选中的文件类型
        self.scan_thread = ScanThread([path], self.selected_extensions)
        self.scan_thread.file_found.connect(self.on_file_found)
        self.scan_thread.scan_finished.connect(self.on_scan_finished)
        
        # 更新UI状态
        self.scan_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        # 显示正在扫描的文件类型
        type_names = [checkbox.text() for ext, checkbox in self.file_type_checkboxes.items() 
                     if ext in self.selected_extensions]
        self.statusBar().showMessage(f"正在扫描{', '.join(type_names)}文件...")
        self.scan_thread.start()

    def stop_scan(self):
        """停止扫描"""
        if self.scan_thread and self.scan_thread.isRunning():
            self.scan_thread.stop()
            self.statusBar().showMessage("正在停止扫描...")

    def on_scan_finished(self):
        """扫描完成处理"""
        self.scan_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)
        count = self.file_model.rowCount()
        self.statusBar().showMessage(f"扫描完成，共找到 {count} 个文件")

    def filter_files(self):
        """增强的文件过滤功能，支持任意字符和完全匹配搜索，同时支持在备注中搜索"""
        search_text = self.search_input.text().strip()
        search_mode = self.search_mode.currentText()
        
        # 如果搜索文本为空，显示所有文件
        if not search_text:
            self.reset_search()
            return
        
        # 过滤文件
        original_files = getattr(self, '_original_files', self.file_model.files)
        filtered_files = []
        
        for file_info in original_files:
            filename = file_info['name']
            file_path = file_info['path']
            
            # 获取文件备注
            note = self.get_note(file_path)
            
            if search_mode == "任意字符":
                # 任意字符搜索（包含）- 同时检查文件名和备注
                search_lower = search_text.lower()
                if (search_lower in filename.lower() or 
                    search_lower in note.lower()):
                    filtered_files.append(file_info)
            elif search_mode == "完全匹配":
                # 完全匹配搜索 - 只匹配文件名
                if filename.lower() == search_text.lower():
                    filtered_files.append(file_info)
            elif search_mode == "备注搜索":
                # 备注搜索 - 只在备注中搜索
                search_lower = search_text.lower()
                if search_lower in note.lower():
                    filtered_files.append(file_info)
        
        # 更新文件模型
        self.file_model.beginResetModel()
        self.file_model.files = filtered_files
        self.file_model.endResetModel()
        
        # 更新计数标签和状态栏
        count = len(filtered_files)
        self.count_label.setText(f"找到: {count} 个文件")
        self.statusBar().showMessage(f"搜索结果: '{search_text}' 匹配 {count} 个文件")
    
    def reset_search(self):
        """重置搜索，显示所有文件"""
        # 恢复原始文件列表
        if hasattr(self, '_original_files'):
            self.file_model.beginResetModel()
            self.file_model.files = self._original_files.copy()
            self.file_model.endResetModel()
            
        # 清空搜索输入框
        self.search_input.clear()
        
        # 重置搜索模式为默认值
        self.search_mode.setCurrentIndex(0)  # 0对应"任意字符"模式
        
        # 更新状态信息
        total_count = len(self.file_model.files)
        self.count_label.setText(f"找到: {total_count} 个文件")
        self.statusBar().showMessage("搜索已重置，显示所有文件")
    
    def on_search_text_changed(self, text):
        """搜索文本变化时的处理"""
        # 当文本框清空时，重置搜索
        if not text.strip():
            self.reset_search()
    
    def on_file_found(self, file_info):
        """处理找到的文件"""
        # 保存原始文件列表（只在第一次添加文件时初始化）
        if not hasattr(self, '_original_files'):
            self._original_files = []
        
        self._original_files.append(file_info)
        self.file_model.add_file(file_info)
        count = self.file_model.rowCount()
        self.count_label.setText(f"找到: {count} 个文件")
    
    def start_scan(self):
        """开始扫描"""
        path = self.path_input.text()
        if not path or not os.path.isdir(path):
            QMessageBox.warning(self, "路径错误", "请选择有效的扫描目录")
            return
            
        # 检查是否选择了文件类型
        if not self.selected_extensions:
            QMessageBox.warning(self, "未选择文件类型", "请至少选择一种文件类型进行扫描")
            return

        # 重置界面
        self.file_model.clear_files()
        # 清除原始文件列表缓存
        if hasattr(self, '_original_files'):
            delattr(self, '_original_files')
        self.count_label.setText("找到: 0 个文件")
        
        # 启动扫描线程，传递选中的文件类型
        self.scan_thread = ScanThread([path], self.selected_extensions)
        self.scan_thread.file_found.connect(self.on_file_found)
        self.scan_thread.scan_finished.connect(self.on_scan_finished)
        
        # 更新UI状态
        self.scan_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        # 显示正在扫描的文件类型
        type_names = [checkbox.text() for ext, checkbox in self.file_type_checkboxes.items() 
                     if ext in self.selected_extensions]
        self.statusBar().showMessage(f"正在扫描{', '.join(type_names)}文件...")
        self.scan_thread.start()

    def show_context_menu(self, position):
        """显示右键菜单"""
        index = self.file_table.indexAt(position)
        if not index.isValid():
            return

        menu = QMenu()
        
        # 打开文件
        open_file_action = QAction("打开文件", self)
        open_file_action.triggered.connect(lambda: self.open_file(index))
        menu.addAction(open_file_action)
        
        # 添加备注
        note_action = QAction("添加/编辑备注", self)
        note_action.triggered.connect(lambda: self.add_note(index))
        menu.addAction(note_action)
        
        # 复制路径
        copy_action = QAction("复制文件路径", self)
        copy_action.triggered.connect(lambda: self.copy_file_path(index))
        menu.addAction(copy_action)
        
        # 打开文件位置（移到复制到自定义文件夹旁边）
        open_action = QAction("打开文件位置", self)
        open_action.triggered.connect(lambda: self.open_file_location(index))
        menu.addAction(open_action)
        
        # 复制到自定义文件夹
        copy_to_folder_action = QAction("复制到自定义文件夹", self)
        copy_to_folder_action.triggered.connect(lambda: self.copy_to_custom_folder(index))
        menu.addAction(copy_to_folder_action)
        
        # 文件改名
        rename_action = QAction("文件改名", self)
        rename_action.triggered.connect(lambda: self.rename_file(index))
        menu.addAction(rename_action)
        
        # 删除文件
        delete_action = QAction("删除文件", self)
        delete_action.triggered.connect(lambda: self.delete_file(index))
        menu.addAction(delete_action)
        
        menu.exec_(self.file_table.viewport().mapToGlobal(position))

    def open_file_location(self, index):
        """打开文件所在目录"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if file_info:
            try:
                # 打开文件所在的文件夹
                path = file_info['path']
                # 确保路径格式正确
                path = os.path.normpath(path)
                # 获取文件所在目录
                directory = os.path.dirname(path)
                
                # 验证目录是否存在
                if os.path.isdir(directory):
                    # 使用os.startfile打开文件夹
                    os.startfile(directory)
                else:
                    QMessageBox.warning(self, "操作失败", f"目录不存在: {directory}")
            except Exception as e:
                # 显示更详细的错误信息
                QMessageBox.warning(self, "操作失败", f"无法打开文件位置: {str(e)}\n文件路径: {path}\n目录路径: {directory}")

    def open_file(self, index):
        """直接打开文件"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if file_info:
            try:
                os.startfile(file_info['path'])  # Windows原生方式打开
            except Exception as e:
                QMessageBox.warning(self, "操作失败", f"无法打开文件: {str(e)}")

    def copy_file_path(self, index):
        """复制文件路径到剪贴板"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if file_info:
            clipboard = QApplication.clipboard()
            clipboard.setText(file_info['path'])
            self.statusBar().showMessage("文件路径已复制到剪贴板")
    
    def copy_to_custom_folder(self, index):
        """复制文件到用户选择的自定义文件夹"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if not file_info:
            return
            
        source_path = file_info['path']
        source_file_name = file_info['name']
        
        # 让用户选择目标文件夹
        dest_folder = QFileDialog.getExistingDirectory(self, "选择目标文件夹", os.path.dirname(source_path))
        
        if not dest_folder:
            return  # 用户取消了操作
        
        # 构建目标文件路径
        dest_path = os.path.join(dest_folder, source_file_name)
        
        # 如果目标文件已存在，询问是否覆盖
        if os.path.exists(dest_path):
            reply = QMessageBox.question(self, "文件已存在", 
                                      f"文件 '{source_file_name}' 已存在于目标文件夹中。是否覆盖？",
                                      QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply != QMessageBox.Yes:
                return
        
        try:
            # 复制文件
            shutil.copy2(source_path, dest_path)
            QMessageBox.information(self, "复制成功", f"文件 '{source_file_name}' 已成功复制到目标文件夹。")
        except Exception as e:
            QMessageBox.warning(self, "复制失败", f"无法复制文件: {str(e)}")
    
    def rename_file(self, index):
        """重命名选中的文件"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if not file_info:
            return
            
        file_path = file_info['path']
        current_name = file_info['name']
        directory = os.path.dirname(file_path)
        
        # 获取文件名（不含扩展名）和扩展名
        name_without_ext, ext = os.path.splitext(current_name)
        
        # 弹出输入对话框
        new_name, ok = QInputDialog.getText(
            self, "文件改名", 
            f"请输入新文件名（包含扩展名）:", 
            text=current_name
        )
        
        if not ok or new_name.strip() == "":
            return  # 用户取消或输入为空
        
        # 检查文件名是否与原文件名相同
        if new_name == current_name:
            return
        
        # 构建新文件路径
        new_file_path = os.path.join(directory, new_name)
        
        # 检查新文件名是否已存在
        if os.path.exists(new_file_path):
            QMessageBox.warning(self, "重命名失败", f"文件名 '{new_name}' 已存在！")
            return
        
        try:
            # 执行文件重命名
            os.rename(file_path, new_file_path)
            
            # 更新模型中的文件信息
            file_info['name'] = new_name
            file_info['path'] = new_file_path
            
            # 刷新表格视图
            self.file_model.dataChanged.emit(
                self.file_model.index(index.row(), 0),
                self.file_model.index(index.row(), 4)
            )
            
            self.statusBar().showMessage(f"文件已成功重命名为 '{new_name}'")
            
        except Exception as e:
            QMessageBox.warning(self, "重命名失败", f"无法重命名文件: {str(e)}")

    def delete_file(self, index):
        """删除选中的文件，带确认提示"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if not file_info:
            return
            
        file_path = file_info['path']
        file_name = file_info['name']
        
        # 二次确认删除操作
        reply = QMessageBox.question(self, "确认删除", 
                                  f"确定要删除文件 '{file_name}' 吗？此操作不可撤销。",
                                  QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        
        if reply != QMessageBox.Yes:
            return
        
        try:
            # 删除文件
            os.remove(file_path)
            
            # 从模型中移除文件条目
            self.file_model.beginRemoveRows(QModelIndex(), index.row(), index.row())
            self.file_model.files.pop(index.row())
            self.file_model.endRemoveRows()
            
            # 更新计数
            self.count_label.setText(f"找到: {len(self.file_model.files)} 个文件")
            self.statusBar().showMessage(f"文件 '{file_name}' 已成功删除")
            
        except Exception as e:
            QMessageBox.warning(self, "删除失败", f"无法删除文件: {str(e)}")

    def add_note(self, index):
        """添加或编辑文件备注"""
        if not index.isValid():
            return
            
        file_info = self.file_model.get_file(index.row())
        if not file_info:
            return
            
        file_path = file_info['path']
        note = self.get_note(file_path)
        
        # 弹出输入对话框
        new_note, ok = QInputDialog.getMultiLineText(
            self, "添加备注", f"为文件添加备注:\n{file_info['name']}", note
        )
        
        if ok:
            self.save_note(file_path, new_note)
            self.statusBar().showMessage("备注已保存")

    def get_note(self, file_path):
        """从数据库获取备注"""
        try:
            conn = sqlite3.connect('ppt_scanner.db')
            c = conn.cursor()
            c.execute("SELECT note FROM file_notes WHERE path=?", (file_path,))
            result = c.fetchone()
            conn.close()
            return result[0] if result else ""
        except Exception as e:
            QMessageBox.warning(self, "数据库错误", f"获取备注失败: {str(e)}")
            return ""

    def save_note(self, file_path, note):
        """保存备注到数据库"""
        try:
            conn = sqlite3.connect('ppt_scanner.db')
            c = conn.cursor()
            c.execute("REPLACE INTO file_notes (path, note) VALUES (?, ?)", 
                     (file_path, note))
            conn.commit()
            conn.close()
        except Exception as e:
            QMessageBox.warning(self, "数据库错误", f"保存备注失败: {str(e)}")

    def closeEvent(self, event):
        """窗口关闭事件处理"""
        if self.scan_thread and self.scan_thread.isRunning():
            reply = QMessageBox.question(
                self, "确认", "扫描正在进行中，确定要退出吗？",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No
            )
            if reply == QMessageBox.Yes:
                self.scan_thread.stop()
                self.scan_thread.wait()
                event.accept()
            else:
                event.ignore()
        else:
            event.accept()

if __name__ == "__main__":
    # 确保中文显示正常
    font = QFont("Microsoft YaHei")
    
    app = QApplication(sys.argv)
    app.setFont(font)
    
    # 设置应用风格
    app.setStyle("Fusion")
    
    window = PPTScanner()
    window.show()
    
    sys.exit(app.exec_())